package mxmf.utils;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.fasterxml.jackson.databind.ObjectMapper;

import chances.smart.commons.exception.UserTokenException;
import mxmf.data.DataInfo;
import mxmf.data.Permission;
import mxmf.entity.system.Partner;

@Component
public class PermissionHelper {

    @Value("${chances.auth.key:87651234}")
    private String key;


    private ObjectMapper objectMapper = ObjectMapperHelper.createObjectMapper();

    public static boolean isPermissionAll(String[] codes) {
        if (ArrayUtils.isEmpty(codes)) {
            return false;
        }
        for (String code : codes) {
            if (Permission.STAR.equals(code)) {
                return true;
            }
        }
        return false;
    }

    public List<Permission> getCpPermissions() {
        DataInfo dataInfo = createDataInfo();
        return dataInfo.getCpList();
    }

    public String[] getCpCodes() {
        List<Permission> cpList = getCpPermissions();
        String[] cpCodes = getPermission(cpList);
        String[] disCodes = this.getDisableCodes();
        if (isPermissionAll(cpCodes) && disCodes.length > 0) {
            List<Partner> allPartner = new ArrayList<Partner>();
            List<String> cpCodeList = allPartner.stream()
                    .filter(p -> Partner.TYPE_CP.equals(p.getType())
                            && Partner.ENABLE == p.getEnableStatus())
                    .map(Partner::getCode).collect(Collectors.toList());
            cpCodes = new String[cpCodeList.size()];
            cpCodeList.toArray(cpCodes);
        }
        return cpCodes;
    }

    public List<Permission> getTypeCodePermissions() {
        DataInfo dataInfo = createDataInfo();
        return dataInfo.getTypeCodeList();
    }

    public String[] getTypeCodes() {
        List<Permission> typeCodeList = getTypeCodePermissions();
        return getPermission(typeCodeList);
    }

    public List<Permission> getOpCodePermissions() {
        DataInfo dataInfo = createDataInfo();
        return dataInfo.getOpList();
    }

    public String[] getOpCodes() {
        List<Permission> opList = getOpCodePermissions();
        return getPermission(opList);
    }

    public List<Permission> getDisablePermissions() {
        DataInfo dataInfo = createDataInfo();
        return dataInfo.getDisableList();
    }

    public String[] getDisableCodes() {
        List<Permission> disableList = getDisablePermissions();
        if (disableList.isEmpty()) {
            return new String[0];
        }
        Set<String> permission = disableList.parallelStream().map(Permission::getValue)
                .collect(Collectors.toSet());
        return permission.toArray(new String[0]);
    }

    private String[] getPermission(List<Permission> permissions) {
        if (permissions.isEmpty()) {
            return new String[0];
        }
        Optional<Permission> permissionAll = permissions.parallelStream()
                .filter(cp -> cp.isValueStar()).findFirst();
        if (permissionAll.isPresent()) {
            return new String[] { Permission.STAR };
        } else {
            Set<String> permission = permissions.parallelStream().map(Permission::getValue)
                    .collect(Collectors.toSet());
            return permission.toArray(new String[0]);
        }
    }

    public DataInfo createDataInfo() {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                    .getRequestAttributes()).getRequest();
            String token = request.getHeader("dataToken");
            byte[] body = Base64.getDecoder().decode(token);
            byte[] source = decrypt(body);
            return objectMapper.readValue(source, DataInfo.class);
        } catch (Exception e) {
            throw new UserTokenException(401, "dataToken error");
        }
    }

    public byte[] decrypt(byte[] src) throws Exception {
        // DES算法要求有一个可信任的随机数源
        SecureRandom random = new SecureRandom();
        // 创建一个DESKeySpec对象
        DESKeySpec desKey = new DESKeySpec(key.getBytes());
        // 创建一个密匙工厂
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        // 将DESKeySpec对象转换成SecretKey对象
        SecretKey securekey = keyFactory.generateSecret(desKey);
        // Cipher对象实际完成解密操作
        Cipher cipher = Cipher.getInstance("DES");
        // 用密匙初始化Cipher对象
        cipher.init(Cipher.DECRYPT_MODE, securekey, random);
        // 真正开始解密操作
        return cipher.doFinal(src);
    }

}
